import { useMemo } from "react";
import { StrType } from "../enumType";

type FormatType = 
| 'YYYY-MM-DD' 
| 'MM/DD/YYYY' 
| 'DD-MM-YYYY'
| 'YYYY年MM月DD日'
| 'HH:mm:ss' 
| 'YYYY-MM-DD HH:mm:ss'
| 'MMM D,YYYY' 
| 'YYYY-MM-DD HH:mm'
| string;

const monthNames = [
    'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
  'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
]

const weekNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];

const dateFormat = (param: Date | string | number | null | undefined, formatType: FormatType = 'YYYY-MM-DD'):string | null => {
    if (!param) return null;
    const result = new Date(param);
    if (isNaN(result.getTime())) return null;

    const pad = (num: number) => num.toString().padStart(2, '0');
    const getQuarter = (month: number) => Math.floor(month / 3) + 1;

    const replacements: Record<string,string> = {
        YYYY: result.getFullYear().toString(),
        YY: result.getFullYear.toString().slice(-2),
        Q: getQuarter(result.getMonth()).toString(),
        MMM: monthNames[result.getMonth()],
        MM: pad(result.getMonth() +1),
        M: (result.getMonth() + 1).toString(),
        DD: pad(result.getDate()),
        D: result.getDate().toString(),
        ddd: weekNames[result.getDay()],
        dd: pad(result.getDay() + 1),
        HH: pad(result.getHours()),
        H: result.getHours().toString(),
        mm: pad(result.getMinutes()),
        m: result.getMinutes().toString(),
        ss: pad(result.getSeconds()),
        s: result.getSeconds().toString()
    };
    return formatType.replace(/YYYY|YY|MMM|MM|M|DD|D|HH|H|mm|m|ss|s/g, match => replacements[match]);
}

const relativeTime = (param: Date,formatType: FormatType = 'YYYY-MM-DD'):string | null => {
    const now = new Date();
    const diff = now.getTime() - param.getTime();

    const minute = 60 * 1000;
    const hour = minute * 60;
    const day = hour * 24;

    if (diff < minute) return '刚刚';
    if (diff < hour) return `${Math.floor(diff/minute)}分钟前`;
    if (diff < day) return `${Math.floor(diff/hour)}小时前`;
    return dateFormat(param, formatType);
}

const relativeTimeV2 = (param: Date | string | number | null | undefined,formatType: FormatType = 'YYYY-MM-DD'):string | null => {
    if (!param) return null;
    const result = new Date(param);
    const now = new Date();
    const diff = now.getTime() - result.getTime();

    const minute = 60 * 1000;
    const hour = minute * 60;
    const day = hour * 24;

    const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();
    const paramTime = result.getTime();

    const yesterdayStart = todayStart - day;

    if (diff < minute * 3) return '刚刚';
    // if (diff < hour) return `${Math.floor(diff/minute)}分钟前`;
    if (paramTime >= todayStart) {
        return dateFormat(result, "HH:mm");
    }
    if (paramTime >= yesterdayStart) {
        return '昨天';
    }
    return dateFormat(result, formatType);
}

const textSplitter = ({text, chunksLength, chunksSize}: {text: string, chunksLength: number, chunksSize: number}): string[] => {
    if (chunksLength <= 0 || typeof chunksLength !== 'number') return [text];
    if (!text || typeof text !== 'string') return [];
    const chunks: string[] = [];
    let currentIndex = 0;
    while (currentIndex < text.length && chunks.length < chunksSize) {
        chunks.push(text.slice(currentIndex, currentIndex + chunksLength));
        currentIndex += chunksLength
    }
    return chunks;
}

const formatFileSize = (bytes: number, decimals: number = 2): string => {
    if (bytes === 0) return '0 Bytes';
    const k = 1024;
    const dm = decimals < 0 ? 0 : decimals;
    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];

    const i = Math.floor(Math.log(bytes) / Math.log(k));
    
    if (i === 0) return `${bytes} ${sizes[i]}`;

    return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
}

const boolsEqual = (
    values: boolean[],
    mode: 'anyFalseIsFalse' | 'anyTrueIsTrue' | 'allEqual' | 'majorityTrue' = "allEqual"
) => {
    switch (mode) {
        case "anyFalseIsFalse":
            return !values.includes(false);
        case "anyTrueIsTrue":
            return values.includes(true);
        case "majorityTrue":
            const trues = values.filter(Boolean).length;
            const falses = values.length - trues;
            return trues > falses;
        case "allEqual":
            return values.every((item) => item === values[0]);
        default:
            return false;
    }
}

const isJsonFormat = (jsonStr: any) => {
    try {
        const parsed = JSON.parse(jsonStr.toString());
        return typeof parsed === 'object' && parsed !== null;
    } catch (err) {
        return false;
    }
}

const getStrType = (str: string) => {
    try {
        const obj = JSON.parse(str);
        if (Array.isArray(obj)) {
            return StrType.ARRAY;
        }
        if (typeof obj === "object" && obj !== null) {
            return StrType.OBJECT;
        }
        return StrType.OTHER;
    } catch (err) {
        return StrType.INVALID;
    }
}

const CleanTimeout = (timeoutkey: string) => {
    const key = timeoutkey + "-TimeoutId"
    const timeoutId = localStorage.getItem(key);
    if (timeoutId) {
        clearTimeout(timeoutId);
        localStorage.removeItem(key);
    }
}

const RecordTimeoutId = (timeoutkey: string, timeoutId: NodeJS.Timeout | string | number) => {
    const key = timeoutkey + "-TimeoutId";
    localStorage.setItem(key, String(timeoutId));
}

export const UtilHelpers = {
    dateFormat,
    relativeTime,
    relativeTimeV2,
    textSplitter,
    formatFileSize,
    boolsEqual,
    isJsonFormat,
    getStrType,
    CleanTimeout,
    RecordTimeoutId
}